package org.example.oop.thread;

import lombok.SneakyThrows;

import java.util.concurrent.*;

/**
 * org.example.oop.thread
 *
 * @author moLei
 * @description 多线程
 *      线程的生命周期:
 *          新建: 线程创建完毕
 *          就绪: 不停的抢cpu执行权,抢到后变为运行状态
 *          阻塞: 执行sleep或wait方法后处于阻塞状态,阻塞状态没有执行资源也没有执行权,等待sleep时间到或者notify等其他方法唤醒后变为就绪状态
 *          ** 运行: 抢到cpu的执行权,运行代码,执行过程中可能被其他线程抢夺执行权,从而处于就绪状态，该状态在java没有定义，线程的运行时是交给操作系统的。运行中的线程不归java控制
 *          等待：线程调用wait方法后处于等待状态，等待被唤醒或者被中断。
 *          计时状态：线程调用sleep方法后处于计时状态，计时结束后变为就绪状态
 *          死亡: 线程执行完毕或者异常结束
 * @since 2025/6/22
 */
public class ThreadDemo {

    /**
     * 线程是操作系统能够进行运算调度的最小单位，包含在进程中，是进程的实际运作单位。
     * cpu是多核多线程的，cpu的每一个线程运行时是单线程的，多线程表示cpu的线程在任务的多个线程中进行切换，充分利用cpu线程执行任务是的空闲时间执行其他线程，提高效率
     *
     *
     * 并发：同一时刻，有多个指令在cpu上交替执行
     * 并行：同一时刻，多个指令在cpu上同时执行
     */

    public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
        // CustomThread thread1 = new CustomThread();
        // CustomThread thread2 = new CustomThread();
        // thread1.start();
        // thread2.start();
        //
        // // 实现Runnable接口
        // Thread thread3 = new Thread(new CustomRunnable());
        // thread3.start();
        // Thread thread4 = new Thread(new Runnable() {
        //     @Override
        //     @SneakyThrows
        //     public void run() {
        //         for (int i = 0; i < 100; i++) {
        //             Thread.sleep(10);
        //             if (i % 10 == 0) {
        //                 Thread.yield();
        //                 System.out.println("Thread-4 yield");
        //             }
        //             System.out.println(Thread.currentThread().getName() + "new Thread(new Runnable)");
        //         }
        //     }
        // });
        // thread4.setName("Thread-4-");
        // thread4.start();
        //
        //
        // // 管理线程的运行结果
        // FutureTask<Integer> ft = new FutureTask<>(new CustomCallable());
        // // 创建线程
        // new Thread(ft).start();
        // System.out.println("Callable线程的运行结果：" + ft.get());
        // 获取指定时间内的结果，超时则抛出异常
        // System.out.println(ft.get(1000, TimeUnit.MILLISECONDS));


        // // 设置线程名字
        // Thread thread = new Thread();
        // // 设置线程名字
        // thread.setName("test-thread-1");
        // // 获取线程名字
        // thread.getName();
        // // 获取当前线程
        // Thread.currentThread();
        // // 让当前线程休眠1000毫秒
        // Thread.sleep(1000);
        // // 设置线程优先级，数字越小优先级越高，cpu会优先调度该线程
        // thread.setPriority(1);
        // 验证线程优先级
        // testThreadPriority();

        // // 获取线程优先级
        // thread.getPriority();
        // // 设置为守护线程,其他非守护线程结束后,守护线程结束
        // thread.setDaemon(true);
        // 验证守护线程
        testDaemonThread();
        // // 出让线程/礼让线程，出让线程表示该线程允许其他同等级的线程执行，不可预测，下一个线程可能也是该线程。要精准的话可以考虑使用wait()/notify()方法或者使用Lock对象
        // // Thread.yield();
        // // 插入线程/插队线程，main线程调用thread线程的join方法，表示main线程会等待thread线程结束后在执行main线程，无参表示无限期等待，加上时间则表示等待指定时间
        // 把指定线程插入当前线程前,指定线程执行完毕后当前线程才继续执行
        // thread3.join();


        System.out.println("main thread terminate");

    }

    /**
     * 验证守护线程,守护线程不是立刻结束,而是陆续结束的,会有延迟
     * 使用场景: 聊天框和文件传输,文件传输设置为守护线程,聊天框设置为用户线程,聊天框结束则文件传输结束
     */
    private static void testDaemonThread() {
        // 守护线程
        Thread daemon = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println(Thread.currentThread().getName() + "         daemon thread " + i);
                }
            }
        });
        // 设置为守护线程
        daemon.setDaemon(true);
        daemon.setName("Thread-daemon");

        // 非守护线程
        Thread userThread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName() + "-----------" + i);
                }
            }
        }, "Thread-user");
        userThread.start();
        daemon.start();
    }

    /**
     * 验证线程的优先级
     */
    private static void testThreadPriority() {
        new Thread(new Runnable() {
            @Override
            @SneakyThrows
            public void run() {
                // 创建锁
                Object lock = new Object();
                for (int i = 0; i < 100; i++) {
                    Thread childThread = new Thread(new Runnable() {
                        @Override
                        @SneakyThrows
                        public void run() {
                            synchronized (lock) {
                                // 创建线程，并让其休眠，等待最后所有的线程一块去争抢资源,wait方法需要锁,且notifyAll是唤醒同一个锁的线程
                                lock.wait();
                                System.out.println(Thread.currentThread().getName() + "==============优先级：" + Thread.currentThread().getPriority());
                            }
                        }
                    }, "Thread-" + i + "-");
                    childThread.setPriority(i % 2 == 0 ? Thread.MIN_PRIORITY : Thread.MAX_PRIORITY);
                    childThread.start();
                }
                // 让线程睡眠，等待所有子线程执行完毕
                Thread.sleep(1000);
                // 所有线程创建完毕后，将所有等待中的线程全部唤醒,notifyAll和wait方法都必须在synchronized代码块中执行,不然他们会抛出异常,提示：IllegalMonitorStateException
                // 因为synchronized代码块中，锁对象是lock对象，所以notifyAll方法中传入的锁对象是lock对象.
                // notify, notifyAll, wait是线程之间通信的方法,他们需要获取到对象监视器(monitor)才能进行.monitor则需要使用同步锁对象才能获取到.
                synchronized (lock) {
                    lock.notifyAll();
                }
            }
        }).start();
    }
}


class CustomThread extends Thread {

    /**
     * 重写run方法，线程执行体
     */
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i % 10 == 0) {
                Thread.yield();
                System.out.println(getName() + "------yield");
            }
            System.out.println(getName() + "-自定义线程");
        }

    }
}

/**
 * 实现Runnable接口
 */
class CustomRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + "-Runnable接口自定义线程");
        }
    }
}

/**
 * 可以获取多线程的运行结果
 */
class CustomCallable implements Callable<Integer> {
    @Override
    public Integer call() {
        int sum = 0;
        for (int i = 0; i < 100; i++) {
            sum += i;
        }
        return sum;
    }
}
